Latest update: July 2013
In this tutorial, we will show you how to poll your FlashAir device contents and make your content list auto refresh. We will use thumbnail.cgi and command.cgi to do this.
We will set the content list we created in Android Tutorial 4: Getting Image Thumbnails to regularly check if the contents of the FlashAir have changed. If they have changed, the content list will update itself. This tutorial will take some of the commands learned in previous tutorials and use them to obtain or display data.
Note: To get the most out of this tutorial, we suggest that you insert your FlashAir device into a digital camera. When you take a new photo or delete a photo, this application will show the changed contents of the FlashAir device.
The list containing the file name and thumbnail pairs of the contents of your FlashAir device will be formatted like this:
                        If you insert your FlashAir device into a digital camera and take a photograph, the content list will refresh itself (after a designated interval of time) and will include the photo that you just took:
                        You will be able to click the name of the new image file and view the photo in a new screen:
                        As you are viewing the image, the image file will download to your Android device.
We will need to create the following files in order to write this application:
                            Important: Please note that your project contains a
                            file called
                            AndroidManifest.xml. This file gives your application particular permissions. By
                            default,
                            applications are not permitted to access the internet. The path to this file should look
                            something
                            like:
                            [Project_Folder]/AndroidManifest.xml
                            
 You will need to add the following lines of code into your
                            AndroidManifest.xml in order for this application to work:
<uses-permission android:name="android.permission.INTERNET" />
                        First, we will write the activity_main.xml file that determines the layout of our Android App. This can be found in your layout folder. The path to this file should look something like: [Project_Folder]/res/layout/activity_main.xml
This file will be identical to the activity_main.xml file from Android Tutorial 3: Downloading Content. Please refer to that tutorial for an explanation of the implementation.
Next, we will create the activity_image_view.xml file that determines the layout of our image viewing screen. This can also be found in your layout folder. The path to this file should look something like: [Project_Folder]/res/layout/activity_image_view.xml
This file will be identical to the activity_image_view.xml file from Android Tutorial 3: Downloading Content. Please refer to that tutorial for an explanation of the implementation.
First, we will get a list of the file names in the desired directory of your FlashAir device (see Android Tutorial 3: Downloading Content for a detailed explanation).
Then we will set each file name in the list to an associated thumbnail, display both the
                            file name
                            and thumbnail pair in a
                            ListView format, and set the behavior of the list. For detailed explanation on
                            the implementation,
                            see
                            Android Tutorial 4: Getting Image Thumbnails
                        
Please take the MainActivity.java code from Android Tutorial 4: Getting Image Thumbnails and copy it into your new MainActivity.java file.
We will replace the
                            class MainActivity declaration, member variables, and
                            onCreate(Bundle savedInstanceState) function with the code below:
public class MainActivity extends Activity implements AdapterView.OnItemClickListener {
    ListView listView;
    ImageView imageView;
    TextView currentDirText;
    TextView numFilesText;
    Button backButton;
    String rootDir = "DCIM";
    String directoryName = rootDir; // Initialize to rootDirectory
    SimpleAdapter listAdapter;
    int checkInterval = 5000;
    Handler updateHandler;
    boolean viewingList;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        viewingList = true; // Start out viewing the list
        try {
            // Set buttons
            getWindow().setTitleColor(Color.rgb(65, 183, 216));
            backButton = (Button)findViewById(R.id.button1);
            backButton.getBackground().setColorFilter(Color.rgb(65, 183, 216), PorterDuff.Mode.SRC_IN);
            backButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if(directoryName.equals(rootDir)) {
                        listRootDirectory();
                    }
                    else {
                        int index = directoryName.lastIndexOf("/");
                        directoryName = directoryName.substring(0, index);
                        listDirectory(directoryName);
                    }
                }
            });
            backButton.setEnabled(false); // Disable in root directory
            listRootDirectory();
        } catch(Exception e) {
            Log.e("ERROR", "ERROR: " + e.toString());
            e.printStackTrace();
        }
        updateHandler = new Handler();
        startUpdate();
    }
                        We have added a few new member variables to our previous
                            MainActivity class. 
int checkInterval, which will set the interval of time (in milliseconds)
                                between status
                                checks of the FlashAir.Handler updateHandler, which will manage the
                                Runnable that we will implement in the functions below.boolean viewingList, which will track whether the user is currently
                                viewing a content
                                list or an image.It is worth noting that we have set the root directory to be the "DCIM" folder (line 8). You do not have to set this as your root directory. Since the "DCIM" folder is the location that most digital cameras store photos, it is set as the root directory for this tutorial.
We will leave the rest of the code in MainActivity.java as is. (This should include the functions to set up the content list.)
We will add the code that handles status checking and updating to the
                            MainActivity.java file. This code should be included inside
                            class MainActivity with the other functions we have previously written. 
If the user is not currently viewing a content list, there is no need to poll the FlashAir device - the content list will get the most current updates when it loads. However, if the user is currently viewing a content list, we will poll the contents of the FlashAir regularly and display any changes.
In order to determine whether the user is viewing a list, we will override a listener
                            function to
                            update the value of the flag variable
                            viewingList declared above (on line 13).
    @Override
        public void onWindowFocusChanged(boolean hasFocus) {
            super.onWindowFocusChanged(hasFocus);
            if(hasFocus) {
                viewingList = true;
            }
            else {
                viewingList = false;
            }
        }
    public boolean checkIfListView() {
        // Check if user is viewing a content list
        if(viewingList) {
            return true;
        }
        return false;
    }
                        The variable flag
                            hasFocus will be true if the screen showing the content list is currently
                            being displayed
                            to the user. Each time the user changes their
                            View, the app will be informed. This will facilitate setting the behavior of
                            the
                            Runnable below.
We will use the following CGI command to get the update status of the FlashAir:
command.cgi with
                                op=102
                                http://flashair/command.cgi?op=102
                                    1 if the FlashAir memory has been updated
                                            0 if the memory has not been updated
                                            The CGI command that gets the update status of your FlashAir will only return
                            1 once. Any future queries before another change is made will return
                            0, as the FlashAir memory has not been updated since the last query. 
To execute this CGI command, we will reuse the FlashAirRequest.java file from Android Tutorial 3: Downloading Content:
The following functions determine the behavior and frequency for auto refreshing the content list.
    public Runnable statusChecker = new Runnable() {
        @Override
        public void run() {
            if (checkIfListView() == true) {
                new AsyncTask<String, Void, String>(){
                    @Override
                    protected String doInBackground(String... params) {
                        return FlashAirRequest.getString(params[0]);
                    }
                    @Override
                    protected void onPostExecute(String status) {
                        if(status.equals("1")) {
                            // Fetch current contents of FlashAir and display list
                            listDirectory(directoryName);
                        }
                    }
                }.execute("http://flashair/command.cgi?op=102");
            }
            updateHandler.postDelayed(statusChecker, checkInterval);
        }
    };
    public void startUpdate() {
        statusChecker.run();    
    }
    public void stopUpdate() {
        updateHandler.removeCallbacks(statusChecker);
    }
                        run() function, which sets the main behavior of the
                                Runnable class.updateHandler assign the
                                statusChecker to perform its
                                run() function in
                                checkInterval milliseconds. Note that this code is executed inside the
                                run() function itself. This means that so long as the
                                updateHandler does not stop running, each time the
                                statusChecker performs its
                                run() function, it is assigned to run again in
                                checkInterval milliseconds.This file will be identical to the
                            class ImageViewActivity from
                            Android Tutorial 3: Downloading Content.
                            Please refer to that tutorial for an explanation
                            of the implementation. 
android_tutorial_05.zip (533KB)
All sample code on this page is licensed under BSD 2-Clause License